#include "cache.h"
 //recibe x config


int inicializarCacheFAT(){
int i;
	for(i=0;i<5;i++)
		CtablaFAT[i].bloque=(-1);
	return 0;
}
int agregarCacheFAT(int bloque,char*bloqueFAT){
	int i,j=-1;
	for(i=0;i<5;i++){
		if(CtablaFAT[i].bloque == -1){
			j=i;
			break;
		}

	}
	if(j!=(-1)){
		CtablaFAT[j].bloque=bloque;
		memcpy(CtablaFAT[i].FAT,bloqueFAT,1024);
		CtablaFAT[i].modificado=0;
		return j;

	}
	else{
		FAT_cache cacheBloque;
		cacheBloque.bloque=bloque;
		memcpy(cacheBloque.FAT,bloqueFAT,1024);
		cacheBloque.modificado=0;
		reemplazarElementoFAT(cacheBloque);
		return 0;
	}
}
int actualizarCacheFAT(int indice){
	int i;
	FAT_cache aux;

	aux.bloque=CtablaFAT[indice].bloque;
	memcpy(aux.FAT,CtablaFAT[indice].FAT,1024);
	aux.modificado=CtablaFAT[indice].modificado;

	for(i=indice;i<0;i--){
		CtablaFAT[i].bloque=CtablaFAT[i-1].bloque;
		memcpy(CtablaFAT[i].FAT,CtablaFAT[i-1].FAT,1024);
		CtablaFAT[i].modificado=CtablaFAT[i-1].modificado;
	}
	CtablaFAT[0].bloque=aux.bloque;
	memcpy(CtablaFAT[0].FAT,aux.FAT,1024);
	CtablaFAT[0].modificado=aux.modificado;

	return 0;
}
/*____________________________________________________*/
int reemplazarElementoFAT(FAT_cache bloque){

	if(CtablaFAT[4].modificado==1)
		realizar_pedido_escritura(CtablaFAT[4].bloque, CtablaFAT[4].FAT);
	CtablaFAT[4].bloque=bloque.bloque;
	memcpy(CtablaFAT[4].FAT,bloque.FAT,1024);
	actualizarCacheFAT(4);
	return 0;
}

/*____________________________________________________*/
int buscarFAT(int bloque){
	int i;
	for(i=0;i<5;i++)
		if(CtablaFAT[i].bloque==bloque)
			return i;
	return (-1);
}
/*____________________________________________________*/

int cachePrincipal(){
	if(4096 <= (tamanioCache*1024)&& (tamanioCache*1024) <= 32768 && tamanioCache%2 == 0){

		cantLugares = tamanioCache;
		laCache = NULL;
		inicializarCacheFAT();
		comandoSIGUSR1();
		}
		else {
			printf("NO VALIDO EL VALOR DE TAMANIO DE CACHE\n");
		cantLugares = 0;
		}

	return 0;
}

cache inicializarCache(char * nombre){
	int i;
	cache nuevoCache;


	//PREPARA CACHE VARIABLE
	nuevoCache.contCache = malloc(sizeof(vector)*cantLugares);
	memset(nuevoCache.nombre,0,33);
	memcpy(nuevoCache.nombre,nombre,strlen(nombre));

	nuevoCache.contCache=malloc(sizeof(vector)*cantLugares);
	for(i=0;i<cantLugares;i++){
				nuevoCache.contCache[i].sector =-1;
				memset(nuevoCache.contCache[i].contenido,0,1024);
	}

	agregarLista(nuevoCache);


	return nuevoCache;
}

int agregarLista(cache var){
	ptrCache ptrNuevo;
	int i;

	ptrNuevo = malloc(sizeof(vector)*cantLugares + sizeof(cache));
	(*ptrNuevo).ptrSiguiente = laCache;
	laCache = ptrNuevo;
	memset((*ptrNuevo).nombre,0,33);
	memcpy((*ptrNuevo).nombre,var.nombre,strlen(var.nombre));

	laCache->contCache=malloc(sizeof(vector)*cantLugares);
	for(i=0;i<cantLugares;i++){
				laCache->contCache[i].modificado =var.contCache[i].modificado;
				laCache->contCache[i].sector =var.contCache[i].sector;
				memcpy(laCache->contCache[i].contenido,var.contCache[i].contenido,1024);
	}
	return 0;
}

int agregarEnCache(cache* var,char* buffer,int sector,int modificado)
{
	int i;
	int libre = (-1);

	for(i=0;i<cantLugares;i++){
		if(var->contCache[i].sector <0){
		libre=i;
		break;}
	}

	if(libre==-1 || i>cantLugares){
		algReemplazoCache(var,buffer,sector,modificado);
		printf("REEMPLAZO\n");
	}

	else{
		memcpy(var->contCache[libre].contenido,buffer,1024);
		var->contCache[libre].sector=sector;
		var->contCache[libre].modificado=modificado;
		eliminarLista(var->nombre);
		agregarLista(*var);
		printf("AGREGAR EN CACHE BLOQUE %i\n",libre);
	}
	return 0;

}

int buscarEnCache(cache* var, int sector)
{
	int i,posicion=0;

	for(i=0;i<cantLugares;i++){
		if(var->contCache[i].sector==sector){

			break;
		}
	}
	posicion=i;

	if(i==cantLugares)
		 return (-1);
	else{
		actualizarCache(var ,var->contCache[i],posicion); return i;}

	printf("ENCONTRE EN CACHE BLOQUE %i\n",i);

}

int algReemplazoCache(cache* var,char* buffer,int sector,int modificado)
{
	int i, j,k;
	vector* auxCache;
	auxCache = malloc(cantLugares * sizeof(vector));

	memcpy(auxCache[0].contenido,buffer,1024);
	auxCache[0].sector=sector;
	auxCache[0].modificado=modificado;
	for(i=0,j=1;j<cantLugares;i++,j++){
		memcpy(auxCache[j].contenido,var->contCache[i].contenido,1024);
		auxCache[j].sector=(var->contCache[i].sector);
		auxCache[j].modificado=modificado;
	}
	if(auxCache[j].modificado==1)
		realizar_pedido_escritura(var->contCache[i].sector,var->contCache[i].contenido);

	for(k=0;k<cantLugares;k++){
		memcpy(var->contCache[k].contenido,auxCache[k].contenido,1024);
		var->contCache[k].sector=(auxCache[k].sector);
		var->contCache[k].modificado=(auxCache[k].modificado);
	}
	free(auxCache);
	eliminarLista(var->nombre);
	agregarLista(*var);
	return 0;

}

int actualizarCache(cache* var, vector buffer, int indice){
	int i, j,k;
	vector* auxCache;
	auxCache = malloc(sizeof(vector)*cantLugares);

	memcpy(auxCache[0].contenido,buffer.contenido,1024);
	auxCache[0].sector=buffer.sector;
	auxCache[0].modificado=buffer.modificado;
	for(i=0,j=1;j<cantLugares;i++,j++){
		if(indice==i)
			j--;
		else{
			memcpy(auxCache[j].contenido,var->contCache[i].contenido,1024);
	        auxCache[j].sector=(var->contCache[i].sector);
	        auxCache[j].modificado=(var->contCache[i].modificado);
		}
	}
	for(k=0;k<cantLugares;k++){
		memcpy(var->contCache[k].contenido,auxCache[k].contenido,1024);
		var->contCache[k].sector=(auxCache[k].sector);
		var->contCache[k].modificado=(auxCache[k].modificado);
	}
	free(auxCache);
	eliminarLista(var->nombre);
	agregarLista(*var);
	return 0;
}

int comandoSIGUSR1(void)
{
	char* ptrToken;
	time_t tiempo = time(0);
    struct tm *tlocal = localtime(&tiempo);
    char hora[128];
    strftime(hora,128,"%d.%m.%y %H:%M:%S",tlocal);
	ptr = fopen("cache_dump.txt","a"); /*el "a" es que CREA o abre un archivo para escritura al final del mismo*/
	ptrCache ptrTemp;
	int i;
	ptrTemp = laCache;
	fprintf(ptr,"--------------------------------------------------\n");
	fprintf(ptr,"Timestamp: %s\n",hora);
	while(ptrTemp != NULL){
		fprintf(ptr,"Archivo: %s\nTamaÃ±o de Bloque de Cache: %dKb\n"
				"Cantidad de Bloques de Cache: %d\n\n",ptrTemp->nombre,tamanioCache,cantLugares);
		for(i =0;i < cantLugares;i++){
			fprintf(ptr,"Contenido de Bloque de Cache %d:\n",i+1);
			if(ptrTemp->contCache[i].sector == -1)
				fprintf(ptr,"\n\n");
			else {
				char aux[512];
				memcpy(aux,ptrTemp->contCache[i].contenido,512);
				ptrToken = strtok(aux,"\0");
				while(ptrToken != NULL){
					fprintf(ptr,"%s",ptrToken);
					ptrToken = strtok(NULL,"\0");
				}
				fprintf(ptr,"\n\n");
			}
		}
		ptrTemp = ptrTemp->ptrSiguiente;
		fprintf(ptr,"\n\n");
	}
	fclose(ptr);
	free(ptrTemp);
	return 0;
}

int eliminarLista(char* valor)
{
	ptrCache ptrTemp;
	ptrCache ptrActual;
	ptrCache ptrAnterior;


	if(strcmp((*laCache).nombre,valor) == 0){
		ptrTemp = laCache;
		laCache = laCache->ptrSiguiente;
		free(ptrTemp);
	}
	else{
		ptrAnterior = laCache;
		ptrActual = laCache->ptrSiguiente;

		while(ptrActual != NULL && strcmp((*ptrActual).nombre,valor) != 0){
			ptrAnterior = ptrActual;
			ptrActual = (*ptrActual).ptrSiguiente;
		}
		if(ptrActual!=NULL){
			ptrTemp = ptrActual;
			(*ptrAnterior).ptrSiguiente = (*ptrActual).ptrSiguiente;
//			free(ptrTemp);
		}
	}

	return 0;
}

/*---------------------------------------------*/

int actualizarCachePATH(int indice){
	int i;
	cachePath aux;
	aux.ruta=malloc(strlen(rutasDisco[indice].ruta)+1);
	aux.data=rutasDisco[indice].data;
	memcpy(aux.ruta,rutasDisco[indice].ruta,strlen(rutasDisco[indice].ruta));
	aux.ruta[strlen(rutasDisco[indice].ruta)]='\0';

	for(i=indice;i<0;i--){
		rutasDisco[i].data=rutasDisco[i-1].data;
		free(rutasDisco[i].ruta);
		rutasDisco[i].ruta=	malloc(strlen(rutasDisco[i-1].ruta)+1);
		memcpy(rutasDisco[i].ruta,rutasDisco[i-1].ruta,strlen(rutasDisco[i-1].ruta));
		rutasDisco[i].ruta[strlen(rutasDisco[i-1].ruta)]='\0';
	}
	rutasDisco[0].data=aux.data;
	free(rutasDisco[0].ruta);
	rutasDisco[0].ruta=	malloc(strlen(aux.ruta)+1);
	memcpy(rutasDisco[0].ruta,aux.ruta,strlen(aux.ruta));
	rutasDisco[0].ruta[strlen(aux.ruta)]='\0';


	return 0;
}
/*____________________________________________________*/
int reemplazarElementoPATH(cachePath bloque){

	free(rutasDisco[19].ruta);
	rutasDisco[19].ruta=	malloc(strlen(bloque.ruta)+1);
	rutasDisco[19].data=bloque.data;
	memcpy(rutasDisco[19].ruta,bloque.ruta,strlen(bloque.ruta));
	rutasDisco[19].ruta[strlen(bloque.ruta)]='\0';
	actualizarCachePATH(19);
	return 0;
}

/*____________________________________________________*/
int buscarPATH(char*ruta){
	int i;
	for(i=0;i<20;i++)
		if(!strcmp(rutasDisco[i].ruta,ruta))
			return i;
	return (-1);
}
/*____________________________________________________*/

int inicializarCachePATH(){
	int i;
	for(i=0;i<20;i++)
		rutasDisco[i].data=(-1);
	return 0;
}

int agregarCachePATH(int bloque,char*path){
	int i,j=-1;
	for(i=0;i<20;i++){
		if(rutasDisco[i].data == -1){
			j=i;
			break;
		}

	}
	if(j!=(-1)){
		rutasDisco[j].ruta=malloc(strlen(path)+1);
		rutasDisco[j].data=bloque;
		memcpy(rutasDisco[j].ruta,path,strlen(path));
		rutasDisco[j].ruta[strlen(path)]='\0';
		return j;

	}
	else{
		cachePath cacheBloque;
		cacheBloque.data=bloque;
		cacheBloque.ruta=malloc(strlen(path)+1);
		memcpy(cacheBloque.ruta,path,strlen(path));
		cacheBloque.ruta[strlen(path)]='\0';
		reemplazarElementoPATH(cacheBloque);
		free(cacheBloque.ruta);
		return 0;
	}
}
